package com.frank.config.redis;

import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author Frank Zou
 * @version v0.0.1
 * @date 2024/2/8
 * @description
 */
public class RedisUtil<K, V> {

    private final RedisTemplate<K, V> redisTemplate;

    public RedisUtil(RedisTemplate<K, V> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    private static final String CACHE_KEY_SEPARATOR = ".";

    /**
     * 构建缓存key
     */
    public static String buildKey(String... strObjs) {
        return String.join(CACHE_KEY_SEPARATOR, strObjs);
    }

    /**
     * 是否存在key
     */
    public boolean exist(K key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 删除key
     */
    public boolean del(K key) {
        return redisTemplate.delete(key);
    }

    public void set(K key, V value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public void setNx(K key, V value, Long time, TimeUnit timeUnit) {
        redisTemplate.opsForValue().setIfAbsent(key, value, time, timeUnit);
    }

    public V get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public Boolean zAdd(K key, V value, Long score) {
        return redisTemplate.opsForZSet().add(key, value, Double.parseDouble(String.valueOf(score)));
    }

    public Long countZSet(K key) {
        return redisTemplate.opsForZSet().size(key);
    }

    public Set<V> rangeZset(K key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    public Long removeZSet(K key, V value) {
        return redisTemplate.opsForZSet().remove(key, value);
    }

    public void removeZSetList(K key, Set<String> value) {
        value.forEach((val) -> redisTemplate.opsForZSet().remove(key, val));
    }

    public Double score(K key, V value) {
        return redisTemplate.opsForZSet().score(key, value);
    }

    public Set<V> rangeByScore(K key, long start, long end) {
        return redisTemplate.opsForZSet().rangeByScore(key, Double.parseDouble(String.valueOf(start)), Double.parseDouble(String.valueOf(end)));
    }

    public void addScore(K key, V obj, double score) {
        redisTemplate.opsForZSet().incrementScore(key, obj, score);
    }

    public Long rank(K key, V obj) {
        return redisTemplate.opsForZSet().rank(key, obj);
    }


    public Set<ZSetOperations.TypedTuple<V>> rankWithScore(K key, long start, long end) {
        return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
    }

    public void putHash(K key, String field, V value) {
        redisTemplate.opsForHash().put(key, field, value);
    }


    public void increment(K key, long increment) {
          redisTemplate.opsForValue().increment(key, increment);
    }

    /**
     * 获取hash表数据并删除
     * @param key redis key
     * @return hash表数据
     */
    public Map<K, V> getHashAndDelete(K key) {
        Map<K, V> result = new HashMap<>();
        Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(key, ScanOptions.NONE);
        while (cursor.hasNext()){
            Map.Entry<Object, Object> entry = cursor.next();
            result.put((K) entry.getKey(), (V) entry.getValue());
            redisTemplate.opsForHash().delete(key, entry.getKey());
        }
        return result;
    }
}